<script
  lang="ts"
  setup
  generic="
    T extends {
      id: number
      stepList: Record<string, any>[]
    },
    C extends object
  "
>
import dayjs from 'dayjs'
import { Button, Modal, Popconfirm, Table, message, Form, Select, Dropdown, Menu, MenuItem } from 'ant-design-vue'
import { type AfterFetchContext, objectOmit } from '@vueuse/core'
import type { IBasic, StepItem } from '../../types/apis/basic'
import type { ColumnsType } from 'ant-design-vue/es/table'
import type NewOrEditBodyVue from './NewOrEditBody.vue'
import type { ComponentExposed } from 'vue-component-type-helpers'
import type { IDict } from '../../types/apis/dict'
import { useGlobalConfigStore } from '../../stores/global-config.store'
import type { IModule } from '~/types/apis/module'
import type { IApiCase } from '~/types/apis/api-case'
import { ref, reactive, computed } from 'vue'
import { handleParams } from '../../utils/internal'
import type ExecuteModalVue from '~/components/Execute/ExecuteModal.vue'

const props = withDefaults(
  defineProps<{
    localizedName: string
    baseApiName: string
    columns: ColumnsType<any>
    defaultConstantSelectOptions: C
    defaultWithStepInstance: T
    defaultWithStepItem: StepItem<T>
    info?: 'ui' | 'api' | 'mix' | 'before',
  }>(),
  {
    info: 'api',
  },
)

// 复选框选中的选项
const state = reactive<{
  selectedRowKeys: Key[];
}>({
  selectedRowKeys: [], // Check here to configure the default column
});


const { selectedModuleId } = storeToRefs(useTemporaryStore())


const { info, baseApiName, defaultWithStepItem, defaultWithStepInstance } = toRefs(props)
const infoValue = info.value;

const route = useRoute()
const router = useRouter()
const [createModalVisible, toggleCreateModalVisible] = useToggle(false)
const { setModules } = useTemporaryStore()

// const controlStepState = ref<'new' | 'edit' | 'default'>('default')
const isEditState = computed(() => route.fullPath.includes('is-edit=true'))

const stepSlotRef = ref<{ serialize: () => void }>()
function setStepSlotRef(ref: { serialize: () => void }) {
  stepSlotRef.value = ref
}

const formModel = ref<T>({ ...defaultWithStepInstance.value, stepList: [] })
const bodyRef = ref<ComponentExposed<typeof NewOrEditBodyVue>>()

const selectedStepNum = ref(-1)
// 追加数据下标
const addIndex = ref(-1)
const globalConfig = useGlobalConfigStore()

let moduleId = selectedModuleId.value
let copySelectedCaseId = ref()
const modules = ref<IModule[]>([])
const caseList = ref([])
const [copyModalVisible, toggleCopyModalVisible] = useToggle(false)

let selectedStep = computed<StepItem<T>>(() => {

  const result = formModel.value.stepList?.length > 0
    ? (formModel.value.stepList[
      selectedStepNum.value <= 0 ? 0 : selectedStepNum.value
    ] as StepItem<T>)
    : defaultWithStepItem.value

  // 把当前选中的编辑数据内容赋值到store，以便能正确更新当前选中的内容
  globalConfig.setSelectedStep(result);

  return result
})

const constantSelectOptions = reactive<C>({
  ...props.defaultConstantSelectOptions,
})

const constantDatabaseSelectOptions = reactive<C>({
  ...props.defaultDatabaseConstantSelectOptions,
})

// 保存按钮状态
let disabledStatus = ref(false)

const { post: fetchCreateApiCase } = useCustomFetch(`/engine-service/api/v1/${baseApiName.value}/save`,
  {
    immediate: false,
    afterFetch(ctx: AfterFetchContext<IBasic>) {
      if (ctx.data && ctx.data.code === 0) {
        message.success(ctx.data.msg ?? '保存成功！')
        router.back()
      }
      // 请求结束，保存按钮可用
      disabledStatus.value = false
      return ctx
    },
  },
)

const { post: fetchUpdateApiCase } = useCustomFetch(
  `/engine-service/api/v1/${baseApiName.value}/update`,
  {
    immediate: false,
    afterFetch(ctx: AfterFetchContext<IBasic>) {
      if (ctx.data && ctx.data.code === 0) {
        message.success(ctx.data.msg ?? '更新成功！')
        router.back()
      }
      // 请求结束，保存按钮可用
      disabledStatus.value = false
      return ctx
    },
  },
)

const fetchGetApiCaseUrl = computed(() =>
  `/engine-service/api/v1/${baseApiName.value}/find?id=${formModel.value.id === -1 ? route.query.id : formModel.value.id}`,
)
const { isFetching, execute: fetchGetApiCase } = useCustomFetch(
  fetchGetApiCaseUrl,
  {
    immediate: false,
    afterFetch(ctx: AfterFetchContext<IBasic<any>>) {
      if (ctx.data && ctx.data.code === 0) {
        formModel.value = {
          ...formModel.value,
          ...ctx.data.data,
          stepList: ctx.data.data.list,
        }
        if(baseApiName.value !== 'base_case'){
            const idList =  ctx.data.data?.beforeCaseIds ? ctx.data.data.beforeCaseIds.split(',').map(Number) : []
            formModel.value.beforeCaseIds = idList
        }
        formModel.value.stepList = formModel.value.stepList.map((item) => ({
          ...defaultWithStepItem.value,
          ...item,
          caseId: formModel.value.id,
        }))
      }
      return ctx
    },
  },
)

const { post: fetchDeleteApiCaseStep } = useCustomFetch(
  `/engine-service/api/v1/${baseApiName.value}_step/delete`,
  {
    immediate: false,
    afterFetch(ctx: AfterFetchContext<IBasic>) {
      if (ctx.data && ctx.data.code === 0) {
        message.success(ctx.data.msg ?? '删除成功！')
      }
      return ctx
    },
  },
)

const { post: fetchUpdateApiCaseStep } = useCustomFetch(
  `/engine-service/api/v1/${baseApiName.value}_step/update`,
  {
    immediate: false,
    afterFetch(ctx: AfterFetchContext<IBasic>) {
      if (ctx.data && ctx.data.code === 0) {
        message.success(ctx.data.msg ?? '更新成功！')
      }
      return ctx
    },
  },
)

const { post: fetchCreateApiCaseStep } = useCustomFetch(
  `/engine-service/api/v1/${baseApiName.value}_step/save`,
  {
    immediate: false,
    async afterFetch(ctx: AfterFetchContext<IBasic>) {
      if (ctx.data && ctx.data.code === 0) {
        await fetchGetApiCase()
        message.success(ctx.data.msg ?? '保存成功！')
      }
      console.info("添加后返回的数据： " + JSON.stringify(ctx))
      return ctx
    },
  },
)

const url = computed(() => {
  const _url = '/engine-service/api/v1/dict/list'
  if (info.value === 'api') {
    return handleParams(_url, {
      category: 'api_relate_field_from, api_relate_type, api_assert_field_from, api_assert_type, api_assert_action, db_assert_action, db_assert_mode',
    })
  } else if (info.value === 'ui') {
    return handleParams(_url, {
      category: 'ui_location_type, mix_relate_field_from, mix_relate_type, mix_assert_field_from, mix_assert_type, mix_assert_action, db_assert_action, db_assert_mode',
    })
  } else {
    return handleParams(_url, {
      category: 'mix_relate_field_from, mix_relate_type, mix_assert_field_from, mix_assert_type, mix_assert_action,ui_location_type, db_assert_action, db_assert_mode',
    })
  }
})
const { execute } = useCustomFetch(url, {
  immediate: false,
  afterFetch(ctx: AfterFetchContext<IBasic<Record<string, IDict[]>>>) {
    if (ctx.data && ctx.data.code === 0) {

      for (const [key, value] of Object.entries(ctx.data.data)) {
        // @ts-expect-error
        constantSelectOptions[key] = value
        // @ts-expect-error
        constantDatabaseSelectOptions[key] = value
      }
      // console.info("查询了字典: " + JSON.stringify(constantSelectOptions))
    }
    return ctx
  },
})


function handleAdd(type: string, index?: number) {
  if (isEditState.value) {
    globalConfig.setControlStepState('new')
    // controlStepState.value = 'new'
  }
  // 给添加类型赋值
  // addType = type
  // resetDefaultWithStepItem()
  console.info("projectId: " + JSON.stringify(globalConfig.config.projectId))
  // 向下追加一条数据
  if (typeof index == 'number') {
    const currentData = formModel.value.stepList[index];
    addIndex.value = index
    console.info("下标： " + index)
    formModel.value.stepList.splice(index + 1, 0, {
     
      ...defaultWithStepItem.value,
      caseId: formModel.value.id,
      type: type,
      environmentId: globalConfig.config.environmentId,
      projectId: globalConfig.config.projectId,
      num: currentData.num + 1,
      isAdd: true
    })
    selectedStepNum.value = index+1
  } else {
    // 最后一条数据
    const lastData = formModel.value.stepList[formModel.value.stepList.length - 1];
    formModel.value.stepList.push({
      ...defaultWithStepItem.value,
      caseId: formModel.value.id,
      type: type,
      environmentId: globalConfig.config.environmentId,
      projectId: globalConfig.config.projectId,
      num: lastData === undefined ? 0 : lastData.num + 1,
      isAdd: false
    })
    selectedStepNum.value = formModel.value.stepList.length === 0 ? 0 : formModel.value.stepList.length - 1
  }

  console.info("当前数据： " + JSON.stringify(formModel.value.stepList[selectedStepNum.value]))

  toggleCreateModalVisible()
}


function handleApiAdd(index?: number) {
  globalConfig.setTestType('API')
  handleAdd('API', index);
  console.info("testType = " + JSON.stringify(globalConfig.testType))
}



function handleUiAdd(index?: number) {
  globalConfig.setTestType('UI')
  handleAdd('UI', index);
  console.info("testType = " + JSON.stringify(globalConfig.testType))
}

function handleAddDatabase(index?: number) {
  globalConfig.setTestType('DATABASE')
  handleAdd('DATABASE', index);
  console.info("testType = " + JSON.stringify(globalConfig.testType))
}
function handleEdit(num: number, record: Record<string, any>) {
  // 需要把类型 = API还是UI还是DATABASE存到store
  globalConfig.setTestType(record.type)

  if (isEditState.value) {
    globalConfig.setControlStepState('edit')
    // controlStepState.value = 'edit'
  }
  selectedStepNum.value = num
  toggleCreateModalVisible()
}

async function handleDelete(num: number) {
  if (isEditState.value) {
    await fetchDeleteApiCaseStep({
      id: formModel.value.stepList[num].id,
    }).execute()

    const selectedRowIndex = state.selectedRowKeys.findIndex((item: any) => item == formModel.value.stepList[num].id)
    state.selectedRowKeys.splice(selectedRowIndex,1)
    console.log(state.selectedRowKeys)
    await fetchGetApiCase()
    return
  }
  formModel.value.stepList = formModel.value.stepList.filter(
    (item) => item.num !== num,
  )
  formModel.value.stepList?.forEach((item, index) => (item.num = index))
}

async function handleOk() {
  console.info("handleOk")

  stepSlotRef.value?.serialize()
  if (isEditState.value) {
    if (globalConfig.controlStepState === 'new') {
      console.info("NewOfEditSteps.vue --- 是new")
      await fetchCreateApiCaseStep(
        objectOmit(selectedStep.value, ['id']),
      ).execute()
    } else {
      console.info("NewOfEditSteps.vue --- 是edit")
      await fetchUpdateApiCaseStep(selectedStep.value).execute()
    }
    // 恢复默认的 StepState
    globalConfig.setControlStepState('default')
    // controlStepState.value = 'default'
  }

  toggleCreateModalVisible()
  selectedStepNum.value = -1
}

async function handleCancel() {
  console.info("id: " + selectedStep.value.id)
  if (addIndex.value !== -1) {
    formModel.value.stepList.splice(addIndex.value + 1, 1)
    addIndex.value = -1
  } else 
  if (selectedStep.value.id === -1) {
    // 如果id = -1, 直接删掉id = -1的内容，即删除刚才添加但为保存的内容
    // window.location.reload();
    // 把最后一条删除
    formModel.value.stepList.pop()
  }
   // 把当前选中的数据换成上一条
   selectedStepNum.value = - 1


  toggleCreateModalVisible(false)

}


function handleSave() {
  if(typeof formModel.value.beforeCaseIds === 'object'){
     formModel.value.beforeCaseIds = formModel.value.beforeCaseIds.join(',')
  }
  // 保存按钮置灰
  disabledStatus.value = true
  if (bodyRef.value?.isEditState) {
    // fetchUpdateApiCase(objectOmit(formModel.value, ['stepList'])).execute()
    fetchUpdateApiCase(formModel.value).execute()
  } else {
    fetchCreateApiCase(formModel.value).execute()
  }
}

onMounted(async () => {
  await nextTick()
  if (isEditState.value) {
    fetchGetApiCase()
  }
  await execute()
})



// 下面是拖拽控件的ts
const emits = defineEmits<{
  (e: 'onDeviceList', value: string[]): void
}>()

// const dataSource = formModel.value.stepList;

const position = {
  start: undefined as number | undefined,
  end: undefined as number | undefined,
  sourceEl: undefined as undefined | HTMLTableRowElement,
};

// 排序
const reorder = ({ start, end }: { start: number | undefined, end: number | undefined }) => {
  console.info('当前位置: ' + start + ', 变更后的位置:  ' + end);
  if (start !== undefined && end !== undefined) {
    // 替换公式：splice(index,len,[item])--->具体变换方式请看难点.txt
    // index:数组开始下标
    // len: 替换/删除的长度
    // item:替换的值，删除操作的话 item为空
    let temp = formModel.value.stepList[start];
    formModel.value.stepList.splice(start, 1);
    formModel.value.stepList.splice(end, 0, temp);



    let arr: string[] = formModel.value.stepList?.map((item: any) => item.id);
    // 遍历formModel.value.stepList，将num从0开始逐条赋值，即第一条num赋值0，第二条赋值1，以此类推
    for (let i = 0; i < formModel.value.stepList.length; i++) {
      formModel.value.stepList[i].num = i;
    }
    emits('onDeviceList', arr);
  }
};

function customRow(_record: any, index: any) {
  return {
    style: {
      cursor: 'move',
    },
    // 鼠标移入
    onMouseenter: (event: any) => {
      // 兼容IE
      let ev = event || window.event;
      ev.target.draggable = true;
    },
    // 开始拖拽
    onDragstart: (event: any) => {
      // 兼容IE
      let ev = event || window.event;
      // 阻止冒泡
      ev.stopPropagation();
      // 得到源目标数据;
      position.start = index;
      const tr = ev.target as HTMLTableRowElement;
      position.sourceEl = tr;
    },
    // 拖动元素经过的元素
    onDragover: (event: any) => {
      // console.info("经过: " + JSON.stringify(index))
      let ev = event || window.event;
      // 阻止默认行为
      ev.preventDefault();
    },
    // 松开
    onDrop: (event: any) => {
      let ev = event || window.event;
      // 阻止默认行为
      ev.preventDefault();
      position.end = index;
      reorder(position);
      animation(position);
    },
  };
}
// 实现动画效果
function animation({ start, end, sourceEl }: { start: number | undefined, end: number | undefined, sourceEl: any }) {
  // 60 是每行的高度，也可以自动获取，根据情况而定
  let count = 60 * (start! - end!);
  console.info("移动距离: " + count)
  sourceEl.style.translate = `0px ${count}px`;
  setTimeout(() => {
    sourceEl!.style.transition = 'all 0.5s';
    sourceEl!.style.translate = `0px 0px`;
  });
}


const { execute: fetchApiModules, isFetching: loadingWithGetApiModules } =
  useCustomFetch<IModule[]>(
    `/engine-service/api/v1/${baseApiName.value}_module/list`,
    {
      immediate: false,
      async afterFetch(ctx: AfterFetchContext<IBasic<IModule[]>>) {
        if (ctx.data && ctx.data.data.length > 0) {
          // 初始化modules模块列表
          modules.value = ctx.data.data != null ? ctx.data.data : []
          // 初始化默认的用例ID下拉框内容
          const allList = modules.value.filter(item => item.id === moduleId)[0].list
          caseList.value = allList !== null ? allList : [];
          copySelectedCaseId.value = caseList.value[0].id
        } else {
          console.info(`未查到${baseApiName.value}_module数据`)

        }
        return ctx
      },
    },
  )
// --------------------------↓↓↓↓↓复制相关代码↓↓↓↓↓--------------------------


const { post: handlerFetchCopyCase } = useCustomFetch(
  `/engine-service/api/v1/${baseApiName.value}_step/copy`,
  {
    immediate: false,
    async afterFetch(ctx: AfterFetchContext<IBasic<any>>) {
      if (ctx.data && ctx.data.code === 0) {
        message.success(ctx.data.msg ?? '复制成功')
        // 重新刷一遍数据
        await fetchGetApiCase()
        toggleCopyModalVisible(false)
      }
      return ctx
    },
  },
)


// 复选框变化时触发
const onSelectChange = (selectedRowKeys: Key[]) => {
  console.log('selectedRowKeys changed: ', selectedRowKeys);
  state.selectedRowKeys = selectedRowKeys;
};


//点击复制按钮
async function copyCase() {
  if (state.selectedRowKeys.length === 0) {
    message.error("请选择用例，再进行复制")
  } else {
    await fetchApiModules()
    toggleCopyModalVisible(true)
  }

}



// 模块下拉列表更换值
const handleModuleChange = async (value: number) => {
  console.info("要复制到的目标moduleId: " + value)
  // 这里moduleId要等与所选的module，因为这个mouduleId是作为复制case的条件
  moduleId = value
  const allList = modules.value.filter(item => item.id === moduleId)[0].list
  caseList.value = allList !== null ? allList : [];
  // 切换moduleId后，将用例ID下拉框值默认取第一个值
  copySelectedCaseId.value = caseList.value[0].id;
};

/**
 * caseID的下拉框发生变化触发
 */
const handleCaseChange = async (value: number) => {
  console.info("要复制到的目标caseId: " + value)
  copySelectedCaseId.value = value;
};

const handleCopyCase = async () => {
  // 调用复制接口， 参数在这里传
  await handlerFetchCopyCase({ idList: state.selectedRowKeys, caseId: copySelectedCaseId.value }).execute()
}

async function handleCurrentStepCopy(id: number) {
  // 调用复制接口, 固定复制到当前module之下， 参数在这里传
  const copyCase = [id]
  await handlerFetchCopyCase({ idList: copyCase, caseId: formModel.value.id }).execute()
}

// --------------------------↑↑↑↑↑复制相关代码↑↑↑↑↑--------------------------

// 批量执行
const batchExecution = () => {
  executeId.value = formModel.value.id === -1 ? route.query.id : formModel.value.id
  visibleModel.value = true
}


const executeModalRef = ref<ComponentExposed<typeof ExecuteModalVue>>()

const visibleModel = ref(false)
const executeId = ref<number>(-1)
const executeModalColumnsBefore: ColumnsType<any> = [
  {
    key: 'name',
    title: '接口名称',
    dataIndex: 'name',
    align: 'center',
  },
  {
    key: 'path',
    title: '接口地址',
    dataIndex: 'path',
    align: 'center',
  },
  {
    key: 'alreadyRetriesCount',
    title: '重试次数',
    dataIndex: 'value',
    align: 'center',
    width: 90,
  },
  {
    key: 'description',
    title: '步骤描述',
    dataIndex: 'description',
    align: 'center',
  },
]

const executeModalColumnsAfter: ColumnsType<any> = [
  {
    key: 'response',
    title: '接口响应',
    dataIndex: 'response',
    align: 'center',
  },
]


function handleClickForOpenResponseModal(
  content: [
    IApiCaseExecuteList['responseHeader'],
    IApiCaseExecuteList['responseBody'],
  ],
) {
  let resultContent = ''
  const [header, body] = content

  function appendContent(content: string, space: boolean = true) {
    resultContent += `${space ? '  ' : ''}${content}\n`
  }

  appendContent('请求头：', false)
  header.forEach((item) => {
    appendContent(`${item.name}: ${item.value}`)
  })
  appendContent('请求体: ', false)
  if (body === '') appendContent('空')
  else
    for (const line of JSON.stringify(JSON.parse(body), null, 2).split('\n'))
      appendContent(line)

  executeModalRef.value?.setModalDetails('接口响应', resultContent.trim())
}
</script>

<template>
  <div>
    <NewOrEditBody ref="bodyRef" v-model:form-model="formModel" :case-type="infoValue">
      <slot name="body-content" :form-model="formModel" />

      <div space-y-4 :class="[isFetching && 'opacity-50 pointer-events-none cursor-not-allowed']">
        <Button style="margin-right: 20px" type="primary" @click="handleAddDatabase">
          新增DATABASE步骤
        </Button>
        <!-- <Button style="margin-right: 20px;" v-if="infoValue === 'ui' || infoValue === 'api'" type="primary" @click="handleApiAdd"> 新增步骤 </Button> -->
        <Button style="margin-right: 20px" v-if="infoValue === 'mix' || infoValue === 'api' || infoValue === 'before'" type="primary"
          @click="handleApiAdd">
          新增API步骤
        </Button>
        <Button style="margin-right: 20px" v-if="infoValue === 'mix' || infoValue === 'ui' || infoValue === 'before'" type="primary"
          @click="handleUiAdd">
          新增UI步骤
        </Button>
        <Button style="margin-left: 40px" type="primary" @click="copyCase">
          复制步骤
        </Button>
        <Button style="margin-left: 20px" v-if="infoValue !== 'before'" type="primary" :disabled="(isEditState && state.selectedRowKeys.length === 0) || !isEditState" @click="batchExecution">
          批量执行
        </Button>
        <Table :row-selection="{
          selectedRowKeys: state.selectedRowKeys,
          onChange: onSelectChange,
        }" :pagination="false" :columns="columns" :data-source="formModel.stepList" :scroll="{ x: 1500}"
          :loading="isFetching" size="middle" showIndexColumn :customRow="customRow" :row-key="(record) => record.id">

          <template #bodyCell="{ column, record, index }">

            <template v-if="column.key!.toString() === 'operation'">
              <Button type="link" @click="handleEdit(index, record)">编辑</Button>
              <Popconfirm title="确认是否删除此行！（注意此操作不可逆！）" @confirm="handleDelete(index)">
                <Button type="link"><span text-red>删除</span></Button>
              </Popconfirm>
              <Button type="link" @click="handleCurrentStepCopy((record as T).id)">复制</Button>
              <Dropdown>
                <a class="ant-dropdown-link" @click.prevent>
                  向下追加+
                  <DownOutlined />
                </a>
                <template #overlay>
                  <Menu>
                    <MenuItem @click="handleAddDatabase(index)">
                    新增DATABASE步骤
                    </MenuItem>
                    <MenuItem v-if="infoValue === 'mix' || infoValue === 'api'" @click="handleApiAdd(index)">
                    新增API步骤
                    </MenuItem>
                    <MenuItem v-if="infoValue === 'mix' || infoValue === 'ui'" @click="handleUiAdd(index)">
                    新增UI步骤
                    </MenuItem>
                  </Menu>
                </template>
              </Dropdown>
            </template>
            <template v-else-if="typeof record[column.key!.toString()] === 'boolean'">
              <span :class="[
                !record[column.key!.toString()]
                  ? 'text-red-500'
                  : 'text-blue-500',
              ]">
                {{ record[column.key!.toString()] ? '是' : '否' }}
              </span>
            </template>
            <template v-else-if="record[column.key!.toString()] == null &&
              column.key !== 'operation'
              ">
              <span> - </span>
            </template>
            <template v-else-if="['gmtCreate', 'gmtModified'].includes(column.key!.toString())
              ">
              {{
                dayjs(record[column.key!.toString()]).format(
                  'YYYY-MM-DD - HH:mm:ss',
                )
              }}
            </template>
            <template v-else-if="column.key!.toString() === 'id'">
              {{ index }}
            </template> 
            <template v-else>
              <p truncate :title="record[column.key!.toString()]">
                {{ record[column.key!.toString()] }} 
              </p>
            </template>
          </template>
        </Table>

        <Modal v-model:open="createModalVisible" width="50%" @ok="handleOk" @cancel="handleCancel">
          <slot name="model-content" :set-step-slot-ref="setStepSlotRef" :selected-step="selectedStep"
            :constant-select-options="constantSelectOptions" />
        </Modal>

        <!-- 复制用例 -->
        <Modal v-model:open="copyModalVisible" title="复制用例" @ok="handleCopyCase">
          <div style="">
            <Form layout="inline" :label-col="{ span: 4 }" :wrapper-col="{ span: 16 }" autocomplete="off" style="
                display: flex;
                height: 150px;
                flex-direction: column;
                justify-content: space-around;
              ">
              <Form.Item label="模块ID：">
                <Select :default-value="moduleId" @change="handleModuleChange">
                  <Select.Option v-for="{ id, name } in modules" :key="id" :value="id">
                    <Tooltip>{{ name }}</Tooltip>
                  </Select.Option>
                </Select>
              </Form.Item>
              <Form.Item label="用例ID：">
                <Select v-model:value="copySelectedCaseId" @change="handleCaseChange">
                  <Select.Option v-for="{ id, name } in caseList" :key="id" :value="id">
                    <Tooltip>{{ name }}</Tooltip>
                  </Select.Option>
                </Select>
              </Form.Item>
            </Form>
          </div>
        </Modal>
      </div>
    </NewOrEditBody>
    <NewOrEditFooter :name="localizedName" :disabled="disabledStatus" @save="handleSave" />

  <ExecuteModal
    ref="executeModalRef"
    v-model:execute-id="executeId"
    v-model:visible-model="visibleModel"
    v-model:step-id-list="state.selectedRowKeys"
    :expand-columns-after="executeModalColumnsAfter"
    :expand-columns-before="executeModalColumnsBefore"
    :base-name="info"
  >
    <template #bodyCell="{ record, column }">
      <template v-if="column.key === 'response'">
        <Button
          @click="
            handleClickForOpenResponseModal([
              record.responseHeader,
              record.responseBody,
            ])
          "
        >
          查看详情
        </Button>
      </template>
    </template>
  </ExecuteModal>
</div>

</template>

function $emit(arg0: string, val: any) { throw new Error('Function not implemented.') }
